#include <yatak/devices.h>
#include <yatak/port.h>
#include <yatak/isr.h>
#include <screen.h>

//Mouse Driver
//Some code rewritten from code by SANiK
volatile unsigned char mouse_cycle=0;
volatile char mouse_byte[3];
volatile char mouse_x=0;
volatile char mouse_y=0;
volatile char mouse_lbtn, mouse_rbtn;

//Static functions prototypes
static void mouse_wait(unsigned char a_type);
static unsigned char mouse_read();
static void mouse_write(unsigned char a_write);

extern int graphical_mode;
extern unsigned long g_wd, g_ht;

//These are the ACTUAL positions
volatile int mx, my;

//extern int wid;
//extern window_t* window_list;
//extern window_t current_window;

//Cursor
//static char cursor[8] = {0xF0, 0xE0, 0xE0, 0x90, 0x08, 0x0, 0x0, 0x0};


//Mouse functions
static void mouse_handler(registers_t* regs)
{
	/*
	if(!graphical_mode)
		return;
	switch(mouse_cycle)
	{
	case 0:
		mouse_byte[0]=inportb(0x60);
		mouse_cycle++;
      
		mouse_lbtn = mouse_byte[0] & 0x1;	//bit 0
		mouse_rbtn = mouse_byte[0] & 0x2;	//bit 1
      
		//Note: rbtn is 2 when set, lbtn is 1
		break;
	case 1:
		mouse_byte[1]=inportb(0x60);
		mouse_cycle++;
      
		mouse_x=mouse_byte[1];
		mx += mouse_x;
		if (mx >= g_wd)
			mx = g_wd-1;
		if (mx <= 1)
			mx = 1;
		break;
	case 2:
		mouse_byte[2]=inportb(0x60);
		mouse_cycle=0;
      
		mouse_y=mouse_byte[2];
		my -= mouse_y;
		if (my >= g_ht)
			my = g_ht-1;
		if (my <= 1)
			my = 1;
		break;
	}
	//Window focus
	int i;
	for(i = 1; i <= wid; i++)
	{
		if(mouse_lbtn)
		{
			if(mx >= window_list[i].x && mx <= window_list[i].x+window_list[i].width)// && window_list[i].z < 1)
				if(my >= window_list[i].y && my <= window_list[i].y+window_list[i].height)
				{
					// And now redraw the old focus'd window's topbar
					int y, x, j;
					for(y = 1; y < 10; y++)
						for(x = 1; x < current_window.width-1; x++)
							if(g_read_pixel(current_window.x+x,current_window.y+y) != WINDOW_COLOUR_TOPBAR_TEXT)
								plot_pixel(x,y,WINDOW_COLOUR_TOPBAR,current_window.width,(uint32*)current_window.data);
					// The focus'd window needs to be the current window
					current_window = (window_t)window_list[i];
					// Change topbar colour
					// And later we will change oppacity
					// We arent going to touch the text pixels
					for(y = 1; y < 10; y++)
						for(x = 1; x < current_window.width-1; x++)
							if(g_read_pixel(current_window.x+x,current_window.y+y) != WINDOW_COLOUR_TOPBAR_TEXT)
								plot_pixel(x,y,WINDOW_COLOUR_TOPBAR,current_window.width,(uint32*)current_window.data);
					// We now need to edit the Z settings for ALL the windows
					// And change the current_window to z=1
					for(j = 1;j <= wid; j++)
						window_list[j].z--;
					window_list[i].z = 1;
                 	
					// Redraw the window on top
					put_buffer(window_list[i].x,window_list[i].y,window_list[i].width,
                 					window_list[i].height,(uint32*)window_list[i].data);
                 	
                 	// Now update double_buffer
					write_buffer(window_list[i-1].x,window_list[i-1].y,
                 			window_list[i-1].width,window_list[i-1].height,(uint32*)window_list[i-1].data);
					g_put_pixel(mx, my, 0x00FFFFFF);
					return;
				}
		}           
	}
	//Print mouse - TODO
	g_put_pixel(mx, my, 0x00FFFFFF);
	*/
}

static void mouse_wait(unsigned char a_type)
{
	unsigned int _time_out=100000;
	if(a_type==0)
	{
		while(_time_out--) //Data
		{
			if((inportb(0x64) & 1)==1)
			{
				return;
			}
		}
		return;
	}
	else
	{
		while(_time_out--) //Signal
		{
			if((inportb(0x64) & 2)==0)
			{
				return;
			}
		}
		return;
	}
}

static void mouse_write(unsigned char a_write)
{
	//Wait to be able to send a command
	mouse_wait(1);
	//Tell the mouse we are sending a command
	outportb(0x64, 0xD4);
	//Wait for the final part
	mouse_wait(1);
	//Finally write
	outportb(0x60, a_write);
}

static unsigned char mouse_read()
{
	//Get's response from mouse
	mouse_wait(0);
	return inportb(0x60);
}

void init_ps2_mouse()
{
	unsigned char _status;
  
	mx = (int)g_wd/2;
	my = (int)g_ht/2;
 
	//Enable the auxiliary mouse device
	mouse_wait(1);
	outportb(0x64, 0xA8);
 
	//Enable the interrupts
	mouse_wait(1);
	outportb(0x64, 0x20);
	mouse_wait(0);
	_status=(inportb(0x60) | 2);
	mouse_wait(1);
	outportb(0x64, 0x60);
	mouse_wait(1);
	outportb(0x60, _status);
 
	//Tell the mouse to use default settings
	mouse_write(0xF6);
	mouse_read();  //Acknowledge
 
	//Enable the mouse
	mouse_write(0xF4);
	mouse_read();  //Acknowledge

	//Setup the mouse handler
	register_interrupt_handler(IRQ12, &mouse_handler);
} 

int detect_ps2_mouse()
{
	unsigned char tmp = mouse_read();
	if(tmp != 0xFA)
		return 0;	//No mouse
	else
		return 1;	//Mouse there
}
